'use strict';

const role = require('./model/role');
const permission = require('./model/permission');
const group = require('./model/group');
const debug = require('debug')('egg-rbac-plugin');

module.exports = exports = class mongooseStorage {

  constructor(app) {
    this._mongoose = app.mongoose;
    this.group = group(app);
    this.role = role(app);
    this.permission = permission(app);
  }

  // 增
  newRole({ name, alias, permissions }) {
    return this.role.findOne({ name })
      .then(oldRole => {
        if (oldRole === null) {
          const newRole = new this.role();
          newRole.name = name;
          newRole.alias = alias;
          newRole.permissions = permissions;
          return newRole.save();
        }
        return null;
      });
  }

  newGroup({ name, alias, roles }) {
    return this.group.findOne({ name })
      .then(oldGroup => {
        if (oldGroup === null) {
          const newGroup = new this.group();
          newGroup.name = name;
          newGroup.alias = alias;
          newGroup.roles = roles;
          return newGroup.save();
        }
        return null;
      });
  }

  newPermission({ name, alias, category, categoryAlias }) {
    return this.permission.findOne({ name })
      .then(oldPermission => {
        if (oldPermission === null) {
          const newPermission = new this.permission();
          newPermission.name = name;
          newPermission.alias = alias;
          newPermission.category = category;
          newPermission.categoryAlias = categoryAlias;
          return newPermission.save();
        }
        return null;
      });
  }

  addPermission(_id, permissionIds) {
    return this.role.updateOne({ _id }, { $addToSet: { permissions: { $each: permissionIds } }, $set: { updatedAt: Date.now() } });
  }

  addRole(_id, roleIds) {
    return this.group.updateOne({ _id }, { $addToSet: { roles: { $each: roleIds } }, $set: { updatedAt: Date.now() } });
  }

  insertManyPermission(permissions) {
    return this.permission.insertMany(permissions)
      .then(result => {
        return result.insertedIds;
      });
  }

  // 改
  modifyRoleAlias(_id, alias) {
    return this.role.updateOne({ _id }, { $set: { alias, updatedAt: Date.now() } });
  }

  modifyGroupAlias(_id, alias) {
    return this.group.updateOne({ _id }, { $set: { alias, updatedAt: Date.now() } });
  }

  modifyPermissionAlias(_id, alias) {
    return this.permission.updateOne({ _id }, { $set: { alias, updatedAt: Date.now() } });
  }

  modifyPermissionCategory(_id, category, categoryAlias) {
    return this.permission.updateOne({ _id }, { $set: { category, categoryAlias, updatedAt: Date.now() } });
  }

  // 删
  removeRole(_id) {
    return Promise.all([
      this.role.remove({ _id }),
      this.group.updateMany({ roles: _id }, { $pull: { roles: _id }, $set: { updatedAt: Date.now() } })
    ]);
  }

  removeGroup(_id) {
    return this.group.remove({ _id });
  }

  removePermission(_id) {
    return Promise.all([
      this.permission.remove({ _id }),
      this.role.updateMany({ permissions: _id }, { $pull: { permissions: _id }, $set: { updatedAt: Date.now() } })
    ]);
  }

  removeRolePermissions(_id, permissionIds) {
    return this.role.updateOne({ _id }, { $pull: { permissions: { $in: permissionIds } }, $set: { updatedAt: Date.now() } });
  }

  removeGroupRoles(_id, roleIds) {
    return this.group.updateOne({ _id }, { $pull: { roles: { $in: roleIds } }, $set: { updatedAt: Date.now() } });
  }

  // 查
  getRoleByName(name) {
    return this.role.findOne({ name }).populate('permissions');
  }

  getRolesByNames(names) {
    debug('getRolesByNames names = %O', names);
    const opts = [{ path: 'permissions' }];
    return this.role.find({ name: { $in: names } })
      .then(datas => {
        return this.role.populate(datas, opts);
      });
  }

  getRolesByQuery(query, option) {
    debug('getRolesByQuery query = %O, option = %O', query, option);
    const opts = [{ path: 'permissions' }];
    return this.role.find(query, '', option)
      .then(datas => {
        return this.role.populate(datas, opts);
      });
  }

  getAllRoles() {
    const opts = [{ path: 'permissions' }];
    return this.role.find({})
      .then(datas => {
        return this.role.populate(datas, opts);
      });
  }

  getRolesTotal(query) {
    return this.role.count(query);
  }

  getGroupByName(name) {
    return this.group.findOne({ name }).populate({ path: 'roles', populate: { path: 'permissions' } });
  }

  getGroupsByNames(names) {
    debug('getGroupByName names = %O', names);
    const opts = [{ path: 'roles', populate: { path: 'permissions' } }];
    return this.group.find({ name: { $in: names } })
      .then(datas => {
        return this.group.populate(datas, opts);
      });
  }

  getGroupsByQuery(query, option) {
    debug('getGroupsByQuery query = %O, option = %O', query, option);
    const opts = [{ path: 'roles', populate: { path: 'permissions' } }];
    return this.group.find(query, '', option)
      .then(datas => {
        return this.group.populate(datas, opts);
      });
  }

  getAllGroups() {
    const opts = [{ path: 'roles', populate: { path: 'permissions' } }];
    return this.group.find({})
      .then(datas => {
        return this.group.populate(datas, opts);
      });
  }

  getGroupsTotal(query) {
    return this.group.count(query);
  }

  getPermissionByName(name) {
    return this.permission.fineOne({ name });
  }

  getPermissionsByNames(names) {
    debug('getPermissions names = %O', names);
    return this.permission.find({ name: { $in: names } });
  }

  getPermissionsByQuery(query, option) {
    debug('getPermissionsByQuery query = %O, option = %O', query, option);
    return this.permission.find(query, '', option);
  }

  getGroupPermission(name) {
    return this.group.findOne({ name }).populate({ path: 'roles', populate: { path: 'permissions' } })
      .then(group => {
        let arr = [];
        group.roles.forEach(item => {
          arr = arr.concat(item.permissions);
        });
        return arr;
      });
  }

  getAllPermissions() {
    return this.permission.find({});
  }

  getPermissionsTotal(query) {
    return this.permission.count(query);
  }

  getAllPermissionsGroupByCategory(style) {
    if (style == 'VIEWUI') {
      return this.permission.aggregate([
        {
          $group: {
            _id: '$category',
            title: { $first: '$categoryAlias' },
            children: {
              $push: {
                id: '$_id',
                name: '$name',
                title: '$alias',
                checked: false,
                category: '$category',
                categoryAlias: '$categoryAlias',
                cratedAt: '$createdAt',
                updatedAt: '$updatedAt'
              }
            },
            count: { $sum: 1 }
          }
        }
      ]);
    } else {
      return this.permission.aggregate([
        {
          $group: {
            _id: '$category',
            alias: { $first: '$categoryAlias' },
            data: {
              $push: {
                id: '$_id',
                name: '$name',
                alias: '$alias',
                category: '$category',
                categoryAlias: '$categoryAlias',
                cratedAt: '$createdAt',
                updatedAt: '$updatedAt'
              }
            },
            count: { $sum: 1 }
          }
        }
      ]);
    }
  }

};